Coverage Report

Created: 2024-12-19 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\runtime\src\message\util\array.rs
Line
Count
Source
1
// Copyright (c) 2024, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use crate::message::payload::list_base::impl_list_base;
30
use crate::message::WriteTo;
31
use crate::message::{Error, FromBytes, Message};
32
use crate::util::{Size, ToUsize, Wrap};
33
use std::marker::PhantomData;
34
use std::ops::{Index, IndexMut};
35
use std::slice::{Chunks, ChunksMut};
36
37
pub struct IterMut<'a, Item> {
38
    data: ChunksMut<'a, u8>,
39
    useless: PhantomData<Item>,
40
}
41
42
impl<'a, Item> IterMut<'a, Item> {
43
1
    pub fn new(chunks: ChunksMut<'a, u8>) -> Self {
44
1
        Self {
45
1
            data: chunks,
46
1
            useless: PhantomData,
47
1
        }
48
1
    }
49
}
50
51
impl<'a, Item: Wrap<&'a mut [u8]>> Iterator for IterMut<'a, Item> {
52
    type Item = Item;
53
54
5
    fn next(&mut self) -> Option<Self::Item> {
55
5
        self.data.next().map(|v| 
unsafe { Item::wrap_unchecked(v) }4
)
56
5
    }
57
}
58
59
pub struct Iter<'a, Item> {
60
    data: Chunks<'a, u8>,
61
    useless: PhantomData<Item>,
62
}
63
64
impl<'a, Item> Iter<'a, Item> {
65
1
    pub fn new(chunks: Chunks<'a, u8>) -> Self {
66
1
        Self {
67
1
            data: chunks,
68
1
            useless: PhantomData,
69
1
        }
70
1
    }
71
}
72
73
impl<'a, Item: Wrap<&'a [u8]>> Iterator for Iter<'a, Item> {
74
    type Item = Item;
75
76
5
    fn next(&mut self) -> Option<Self::Item> {
77
5
        self.data.next().map(|v| 
unsafe { Item::wrap_unchecked(v) }4
)
78
5
    }
79
}
80
81
#[derive(Copy, Clone, Debug)]
82
pub struct Array<B, T, Item> {
83
    data: B,
84
    len: usize,
85
    useless: PhantomData<T>,
86
    useless1: PhantomData<Item>,
87
}
88
89
impl<B, T, Item> Array<B, T, Item> {
90
    /// Creates an array from raw parts.
91
    /// This function assumes that data has the number of items specified by len.
92
    ///
93
    /// # Arguments
94
    ///
95
    /// * `data`: the data buffer.
96
    /// * `len`: the number of items to be read from the buffer.
97
    ///
98
    /// # Safety
99
    ///
100
    /// A wrong length could result in UB where the array iterator, getter or setter attempts to
101
    /// slice out of bounds with a future optimization in release builds, currently it will only
102
    /// result in a panic.
103
4
    pub unsafe fn from_raw_parts(data: B, len: usize) -> Array<B, T, Item> {
104
4
        Array {
105
4
            data,
106
4
            len,
107
4
            useless: PhantomData,
108
4
            useless1: PhantomData,
109
4
        }
110
4
    }
111
}
112
113
impl<B: AsRef<[u8]>, T, Item: Size> Array<B, T, Item> {
114
0
    pub fn new(data: B) -> Array<B, T, Item> {
115
0
        let len = data.as_ref().len() / Item::SIZE;
116
0
        unsafe { Array::from_raw_parts(data, len) }
117
0
    }
118
}
119
120
impl_list_base!(Array);
121
122
impl<B: AsRef<[u8]>, T, Item> Array<B, T, Item> {
123
2
    pub fn to_ref<Item1>(&self) -> Array<&[u8], T, Item1> {
124
2
        unsafe { Array::from_raw_parts(self.data.as_ref(), self.len) }
125
2
    }
126
}
127
128
impl<B: AsRef<[u8]>, T, Item: Size> Array<B, T, Item> {
129
2
    pub fn from_parts(data: B, len: usize) -> Option<Array<B, T, Item>> {
130
2
        match data.as_ref().len() == len * Item::SIZE {
131
2
            true => Some(unsafe { Array::from_raw_parts(data, len) }),
132
0
            false => None,
133
        }
134
2
    }
135
}
136
137
impl<'a, B: AsRef<[u8]>, T, Item: Size> Array<B, T, Item> {
138
0
    pub fn get(&'a self, index: usize) -> Option<&'a [u8]> {
139
0
        if index >= self.len {
  Branch (139:12): [Folded - Ignored]
  Branch (139:12): [Folded - Ignored]
140
0
            None
141
        } else {
142
0
            let start = index * Item::SIZE;
143
0
            let end = start + Item::SIZE;
144
0
            Some(&self.data.as_ref()[start..end])
145
        }
146
0
    }
147
148
1
    pub fn iter(&'a self) -> Chunks<'a, u8> {
149
1
        self.data.as_ref().chunks(Item::SIZE)
150
1
    }
151
}
152
153
impl<'a, B: AsMut<[u8]>, T, Item: Size> Array<B, T, Item> {
154
0
    pub fn get_mut(&'a mut self, index: usize) -> Option<&'a mut [u8]> {
155
0
        if index >= self.len {
  Branch (155:12): [Folded - Ignored]
  Branch (155:12): [Folded - Ignored]
156
0
            None
157
        } else {
158
0
            let start = index * Item::SIZE;
159
0
            let end = start + Item::SIZE;
160
0
            Some(&mut self.data.as_mut()[start..end])
161
        }
162
0
    }
163
164
1
    pub fn iter_mut(&'a mut self) -> ChunksMut<'a, u8> {
165
1
        self.data.as_mut().chunks_mut(Item::SIZE)
166
1
    }
167
}
168
169
impl<B: AsRef<[u8]>, T, Item: Size> Index<usize> for Array<B, T, Item> {
170
    type Output = [u8];
171
172
24
    fn index(&self, index: usize) -> &Self::Output {
173
24
        if index >= self.len {
  Branch (173:12): [Folded - Ignored]
  Branch (173:12): [Folded - Ignored]
  Branch (173:12): [True: 0, False: 24]
174
0
            panic!("attempt to index item out of bounds, index={}, len={}", index, self.len)
175
24
        }
176
24
        let start = index * Item::SIZE;
177
24
        let end = start + Item::SIZE;
178
24
        &self.data.as_ref()[start..end]
179
24
    }
180
}
181
182
impl<B: AsRef<[u8]> + AsMut<[u8]>, T, Item: Size> IndexMut<usize> for Array<B, T, Item> {
183
8
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
184
8
        if index >= self.len {
  Branch (184:12): [Folded - Ignored]
  Branch (184:12): [Folded - Ignored]
  Branch (184:12): [True: 0, False: 8]
185
0
            panic!("attempt to index item out of bounds, index={}, len={}", index, self.len)
186
8
        }
187
8
        let start = index * Item::SIZE;
188
8
        let end = start + Item::SIZE;
189
8
        &mut self.data.as_mut()[start..end]
190
8
    }
191
}
192
193
impl<'a, T: FromBytes<'a, Output: ToUsize>, Item: Size> FromBytes<'a> for Array<&'a [u8], T, Item> {
194
    type Output = Array<&'a [u8], T, Item>;
195
196
2
    fn from_bytes(slice: &'a [u8]) -> Result<Message<Self::Output>, Error> {
197
2
        let msg = T::from_bytes(slice)
?0
;
198
2
        let control_size = msg.size();
199
2
        let len = msg.into_inner().to_usize();
200
2
        let total_size = control_size + (len * Item::SIZE);
201
2
        if slice.len() < total_size {
  Branch (201:12): [Folded - Ignored]
  Branch (201:12): [True: 0, False: 2]
  Branch (201:12): [Folded - Ignored]
202
0
            Err(Error::Truncated)
203
        } else {
204
2
            let data = &slice[control_size..total_size];
205
2
            Ok(Message::new(
206
2
                total_size,
207
2
                Array {
208
2
                    data,
209
2
                    len,
210
2
                    useless: PhantomData,
211
2
                    useless1: PhantomData,
212
2
                },
213
2
            ))
214
        }
215
2
    }
216
}